<?php
// +----------------------------------------------------------------------
// | OneBase [ 基于ThinkPHP6的开发框架 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2018-2020 https://www.onebase.org All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )+
// +----------------------------------------------------------------------
// | Author: 王勇程 <laughskydragon@qq.com>
// +----------------------------------------------------------------------

declare (strict_types = 1);

namespace app\common\logic;

/**
 * 提现逻辑
 */
class Withdraw extends LogicBase
{
    /**
     * 申请提现
     */
    public function applyWithdraw($data = [])
    {
        $userId = $data['user_id'] ?? 0;
        $amount = $data['amount'] ?? 0;
        $withdrawType = $data['withdraw_type'] ?? 1;
        $accountInfo = $data['account_info'] ?? [];
        $remark = $data['remark'] ?? '';
        
        if (!$userId) {
            return ['code' => 1, 'msg' => '用户ID不能为空', 'data' => []];
        }
        
        if (!$amount || $amount <= 0) {
            return ['code' => 1, 'msg' => '提现金额必须大于0', 'data' => []];
        }
        
        // 检查用户余额
        $userInfo = $this->modelUser->getInfo(['id' => $userId]);
        if (!$userInfo) {
            return ['code' => 1, 'msg' => '用户不存在', 'data' => []];
        }
        
        if ($userInfo['available_amount'] < $amount) {
            return ['code' => 1, 'msg' => '可提现余额不足', 'data' => []];
        }
        
        // 获取提现配置（系统配置）
        $config = $this->getUserWithdrawConfig();
        
        // 验证提现金额范围
        if ($amount < floatval($config['min_amount'])) {
            return ['code' => 1, 'msg' => '提现金额低于最小限制', 'data' => []];
        }
        if ($amount > floatval($config['max_amount'])) {
            return ['code' => 1, 'msg' => '提现金额超过最大限制', 'data' => []];
        }
        
        // 检查当日提现总额限制
        $todayStart = strtotime(date('Y-m-d 00:00:00'));
        $todayEnd = strtotime(date('Y-m-d 23:59:59'));
        $todayWhere = [
            'user_id' => $userId,
            'apply_time' => ['between', [$todayStart, $todayEnd]]
        ];
        $todayAmount = floatval($this->modelWithdrawOrder->getValue($todayWhere, 'SUM(amount)')) ?: 0.0;
        if ($todayAmount + $amount > floatval($config['daily_limit'])) {
            return ['code' => 1, 'msg' => "今日提现总额不能超过{$config['daily_limit']}元", 'data' => []];
        }
        
        // 计算手续费
        $fee = $this->calculateFeeInternal($amount, $config);
        $actualAmount = $amount - $fee;
        
        // 检查实际到账金额
        if ($actualAmount <= 0) {
            return ['code' => 1, 'msg' => '扣除手续费后金额不足', 'data' => []];
        }
        
        // 验证账户信息
        if (empty($accountInfo)) {
            return ['code' => 1, 'msg' => '收款账户信息不能为空', 'data' => []];
        }
        
        // 开始事务
        \think\facade\Db::transaction(function () use ($userId, $amount, $fee, $actualAmount, $withdrawType, $accountInfo, $remark, $config) {
            // 扣除用户可提现余额
            $this->modelUser->updateInfo(['id' => $userId], [
                'available_amount' => ['dec', $amount]
            ]);
            
            // 创建提现申请
            $withdrawData = [
                'user_id' => $userId,
                'amount' => $amount,
                'fee' => $fee,
                'actual_amount' => $actualAmount,
                'withdraw_type' => $withdrawType,
                'account_info' => $accountInfo,
                'withdraw_status' => (!empty($config['auto_audit']) ? 1 : 0),
                'remark' => $remark,
                'apply_time' => time(),
                'create_time' => time(),
                'update_time' => time()
            ];
            
            // 如果自动审核，设置审核时间
            if ($withdrawData['withdraw_status'] == 1) {
                $withdrawData['audit_time'] = time();
                $withdrawData['audit_admin_id'] = 0; // 系统自动审核
            }
            
            $withdrawId = $this->modelWithdrawOrder->insertGetId($withdrawData);
            
            // 记录余额变动日志
            $balanceData = [
                'user_id' => $userId,
                'type' => 'withdraw',
                'amount' => -$amount,
                'balance_before' => $this->modelUser->getValue(['id' => $userId], 'available_amount') + $amount,
                'balance_after' => $this->modelUser->getValue(['id' => $userId], 'available_amount'),
                'description' => "提现申请，申请ID：{$withdrawId}",
                'related_id' => $withdrawId,
                'status' => 1,
                'create_time' => time(),
                'update_time' => time()
            ];
            $this->modelBalanceRecord->updateInfo([], $balanceData);
        });
        
        return ['code' => 0, 'msg' => '提现申请提交成功', 'data' => []];
    }
    
    /**
     * 获取用户提现记录
     */
    public function getUserWithdraws($data = [])
    {
        $userId = $data['user_id'] ?? 0;
        $withdrawStatus = $data['withdraw_status'] ?? null;
        
        if (!$userId) {
            return ['code' => 1, 'msg' => '用户ID不能为空', 'data' => []];
        }
        
        $list = $this->modelWithdrawOrder->getList(['user_id' => $userId, 'withdraw_status' => $withdrawStatus]);
        
        return $list;
    }
    
    /**
     * 获取提现配置
     */
    public function getWithdrawConfig($data = [])
    {
        return $this->getUserWithdrawConfig();
    }
    
    /**
     * 保存提现配置
     */
    public function saveWithdrawConfig($data = [])
    {
        // 验证必要参数
        $requiredFields = ['min_amount', 'max_amount', 'fee_rate', 'fee_min', 'fee_max', 'daily_limit', 'monthly_limit'];
        foreach ($requiredFields as $field) {
            if (!isset($data[$field])) {
                return ['code' => 1, 'msg' => "参数{$field}不能为空", 'data' => []];
            }
        }
        
        // 数据验证
        if ($data['min_amount'] <= 0) {
            return ['code' => 1, 'msg' => '最小提现金额必须大于0', 'data' => []];
        }
        
        if ($data['max_amount'] <= $data['min_amount']) {
            return ['code' => 1, 'msg' => '最大提现金额必须大于最小提现金额', 'data' => []];
        }
        
        if ($data['fee_rate'] < 0 || $data['fee_rate'] > 1) {
            return ['code' => 1, 'msg' => '手续费率必须在0-1之间', 'data' => []];
        }
        
        if ($data['daily_limit'] <= 0) {
            return ['code' => 1, 'msg' => '每日提现次数限制必须大于0', 'data' => []];
        }
        
        if ($data['monthly_limit'] <= 0) {
            return ['code' => 1, 'msg' => '每月提现金额限制必须大于0', 'data' => []];
        }
        
        // 准备保存数据
        $saveData = [
            'min_amount' => $data['min_amount'],
            'max_amount' => $data['max_amount'],
            'fee_rate' => $data['fee_rate'],
            'fee_min' => $data['fee_min'],
            'fee_max' => $data['fee_max'],
            'daily_limit' => $data['daily_limit'],
            'monthly_limit' => $data['monthly_limit'],
            'auto_audit' => $data['auto_audit'] ?? 0,
            'auto_audit_amount' => $data['auto_audit_amount'] ?? 1000,
            'work_days' => $data['work_days'] ?? '1,2,3,4,5',
            'work_start_time' => $data['work_start_time'] ?? '09:00',
            'work_end_time' => $data['work_end_time'] ?? '18:00',
            'status' => 1,
            'update_time' => time()
        ];
        
        // 检查是否已有配置
        $existConfig = $this->modelWithdrawConfig->getInfo(['status' => 1]);
        
        if ($existConfig) {
            // 更新现有配置
            $result = $this->modelWithdrawConfig->updateInfo(['id' => $existConfig['id']], $saveData);
        } else {
            // 创建新配置
            $saveData['create_time'] = time();
            $result = $this->modelWithdrawConfig->insertGetId($saveData);
        }
        
        if ($result) {
            return ['code' => 0, 'msg' => '配置保存成功', 'data' => []];
        } else {
            return ['code' => 1, 'msg' => '配置保存失败', 'data' => []];
        }
    }
    
    /**
     * 计算提现手续费
     */
    public function calculateWithdrawFee($data = [])
    {
        $amount = $data['amount'] ?? 0;
        
        if (!$amount || $amount <= 0) {
            return ['code' => 1, 'msg' => '金额必须大于0', 'data' => []];
        }
        
        $config = $this->getUserWithdrawConfig();
        $fee = $this->calculateFeeInternal($amount, $config);
        $actualAmount = $amount - $fee;
        
        return ['code' => 0, 'msg' => '计算成功', 'data' => [
            'amount' => $amount,
            'fee' => $fee,
            'actual_amount' => $actualAmount
        ]];
    }
    
    /**
     * 取消提现申请
     */
    public function cancelWithdraw($data = [])
    {
        $userId = $data['user_id'] ?? 0;
        $withdrawId = $data['withdraw_id'] ?? 0;
        
        if (!$userId) {
            return ['code' => 1, 'msg' => '当前状态不允许取消', 'data' => []];
        }
        
        if (!$withdrawId) {
            return ['code' => 1, 'msg' => '当前状态不允许取消', 'data' => []];
        }
        
        // 获取提现申请
        $withdraw = $this->modelWithdrawOrder->getInfo(['id' => $withdrawId, 'user_id' => $userId]);
        if (!$withdraw) {
            return ['code' => 1, 'msg' => '提现申请不存在', 'data' => []];
        }
        
        // 只有待审核状态才能取消
        if ($withdraw['withdraw_status'] != 0) {
            return ['code' => 1, 'msg' => '当前状态不允许取消', 'data' => []];
        }
        
        // 开始事务
        \think\facade\Db::transaction(function () use ($withdraw) {
            // 更新提现状态
            $this->modelWithdrawOrder->updateInfo(['id' => $withdraw['id']], [
                'withdraw_status' => 4, // 已取消
                'update_time' => time()
            ]);
            
            // 退还用户可提现余额
            $currentBalance = $this->modelUser->getValue(['id' => $withdraw['user_id']], 'available_amount');
            $this->modelUser->updateInfo(['id' => $withdraw['user_id']], [
                'available_amount' => ['inc', $withdraw['amount']]
            ]);
            
            // 记录余额变动日志
            $balanceData = [
                'user_id' => $withdraw['user_id'],
                'type' => 'refund',
                'amount' => $withdraw['amount'],
                'balance_before' => $currentBalance,
                'balance_after' => $currentBalance + $withdraw['amount'],
                'description' => "取消提现申请，申请ID：{$withdraw['id']}",
                'related_id' => $withdraw['id'],
                'status' => 1,
                'create_time' => time(),
                'update_time' => time()
            ];
            $this->modelBalanceRecord->updateInfo([], $balanceData);
        });
        
        return ['code' => 0, 'msg' => '取消成功', 'data' => []];
    }
    
    /**
     * 管理员审核提现申请
     */
    public function auditWithdraw($data = [])
    {
        $withdrawId = $data['withdraw_id'] ?? 0;
        $withdrawStatus = $data['withdraw_status'] ?? 0;
        $adminId = $data['admin_id'] ?? 0;
        $adminRemark = $data['admin_remark'] ?? '';
        
        if (!$withdrawId) {
            return ['code' => 1, 'msg' => '提现申请ID不能为空', 'data' => []];
        }
        
        if (!in_array($withdrawStatus, [1, 3])) { // 1=审核通过，3=已拒绝
            return ['code' => 1, 'msg' => '审核状态错误', 'data' => []];
        }
        
        if (!$adminId) {
            return ['code' => 1, 'msg' => '管理员ID不能为空', 'data' => []];
        }
        
        // 获取提现申请
        $withdraw = $this->modelWithdrawOrder->getInfo(['id' => $withdrawId]);
        if (!$withdraw) {
            return ['code' => 1, 'msg' => '提现申请不存在', 'data' => []];
        }
        
        // 只有待审核状态才能审核
        if ($withdraw['withdraw_status'] != 0) {
            return ['code' => 1, 'msg' => '当前状态不允许审核', 'data' => []];
        }
        
        // 如果是拒绝，需要退还用户余额
        if ($withdrawStatus == 3) {
            \think\facade\Db::transaction(function () use ($withdraw, $withdrawStatus, $adminId, $adminRemark) {
                // 更新提现状态
                $this->modelWithdrawOrder->auditWithdraw($withdraw['id'], $withdrawStatus, $adminId, $adminRemark);
                
                // 退还用户可提现余额
                $currentBalance = $this->modelUser->getValue(['id' => $withdraw['user_id']], 'available_amount');
                $this->modelUser->updateInfo(['id' => $withdraw['user_id']], [
                    'available_amount' => ['inc', $withdraw['amount']]
                ]);
                
                // 记录余额变动日志
                $balanceData = [
                    'user_id' => $withdraw['user_id'],
                    'type' => 'refund',
                    'amount' => $withdraw['amount'],
                    'balance_before' => $currentBalance,
                    'balance_after' => $currentBalance + $withdraw['amount'],
                    'description' => "提现申请被拒绝，申请ID：{$withdraw['id']}",
                    'related_id' => $withdraw['id'],
                    'status' => 1,
                    'create_time' => time(),
                    'update_time' => time()
                ];
                $this->modelBalanceRecord->updateInfo([], $balanceData);
            });
        } else {
            // 审核通过
            $this->modelWithdrawOrder->auditWithdraw($withdraw['id'], $withdrawStatus, $adminId, $adminRemark);
        }
        
        $statusText = $withdrawStatus == 1 ? '审核通过' : '已拒绝';
        return ['code' => 0, 'msg' => '审核' . $statusText . '成功', 'data' => []];
    }
    
    /**
     * 确认打款
     */
    public function confirmPay($data = [])
    {
        $withdrawId = $data['withdraw_id'] ?? 0;
        $adminId = $data['admin_id'] ?? 0;
        $adminRemark = $data['admin_remark'] ?? '';
        
        if (!$withdrawId) {
            return ['code' => 1, 'msg' => '提现申请ID不能为空', 'data' => []];
        }
        
        if (!$adminId) {
            return ['code' => 1, 'msg' => '管理员ID不能为空', 'data' => []];
        }
        
        // 获取提现申请
        $withdraw = $this->modelWithdrawOrder->getInfo(['id' => $withdrawId]);
        if (!$withdraw) {
            return ['code' => 1, 'msg' => '提现申请不存在', 'data' => []];
        }
        
        // 只有审核通过状态才能确认打款
        if ($withdraw['withdraw_status'] != 1) {
            return ['code' => 1, 'msg' => '当前状态不允许确认打款', 'data' => []];
        }
        
        // 确认打款
        $this->modelWithdrawOrder->confirmPay($withdraw['id'], $adminId, $adminRemark);
        
        return ['code' => 0, 'msg' => '确认打款成功', 'data' => []];
    }
    
    /**
     * 获取提现统计
     */
    public function getWithdrawStatistics($data = [])
    {
        $startTime = $data['start_time'] ?? null;
        $endTime = $data['end_time'] ?? null;
        
        if ($startTime) {
            $startTime = strtotime($startTime);
        }
        
        if ($endTime) {
            $endTime = strtotime($endTime);
        }
        
        $statistics = $this->modelWithdrawOrder->getWithdrawStatistics($startTime, $endTime);
        
        return ['code' => 0, 'msg' => '获取成功', 'data' => $statistics];
    }
    
    /**
     * 审核提现申请
     * @param array $data
     * @return array
     */
    public function withdrawReview($data = [])
    {
        $withdrawId = $data['withdraw_id'] ?? 0;
        $withdrawStatus = $data['withdraw_status'] ?? 0;
        $adminId = $data['admin_id'] ?? 0;
        $adminRemark = $data['admin_remark'] ?? '';
        
        if (!$withdrawId || !in_array($withdrawStatus, [1, 3])) {
            return ['code' => 1, 'msg' => '参数错误', 'data' => []];
        }
        
        $withdrawInfo = $this->modelWithdrawOrder->getInfo(['id' => $withdrawId]);
        if (!$withdrawInfo) {
            return ['code' => 1, 'msg' => '提现申请不存在', 'data' => []];
        }
        
        // 只能审核待审核状态的申请
        if ($withdrawInfo['withdraw_status'] != 0) {
            return ['code' => 1, 'msg' => '该申请已被审核', 'data' => []];
        }
        
        // 开启事务
        \think\facade\Db::startTrans();
        try {
            $updateData = [
                'withdraw_status' => $withdrawStatus,
                'admin_id' => $adminId,
                'admin_remark' => $adminRemark,
                'review_time' => time()
            ];
            
            $this->modelWithdrawOrder->updateInfo(['id' => $withdrawId], $updateData);
            
            // 如果是拒绝，需要退还用户余额
            if ($withdrawStatus == 3) {
                $this->modelUser->updateInfo(
                    ['id' => $withdrawInfo['user_id']], 
                    ['balance' => ['inc', $withdrawInfo['amount']]]
                );
                
                // 记录余额变动日志
                $this->logicUserBalance->addBalanceLog([
                    'user_id' => $withdrawInfo['user_id'],
                    'type' => 'withdraw_reject',
                    'amount' => $withdrawInfo['amount'],
                    'description' => '提现申请被拒绝，退还余额'
                ]);
            }
            
            \think\facade\Db::commit();
            
            $statusText = $withdrawStatus == 1 ? '通过' : '拒绝';
            return ['code' => 0, 'msg' => '审核' . $statusText . '成功', 'data' => []];
        } catch (\Exception $e) {
            return ['code' => 1, 'msg' => '审核失败：' . $e->getMessage(), 'data' => []];
        }
    }

    /**
     * 查询提现状态
     */
    public function queryWithdrawStatus($data = [])
    {
        $withdrawId = $data['withdraw_id'] ?? 0;

        if (!$withdrawId) {
            return ['code' => 1, 'msg' => '参数错误', 'data' => []];
        }

        $withdrawInfo = $this->modelWithdrawOrder->getInfo(['id' => $withdrawId]);
        if (!$withdrawInfo) {
            return ['code' => 1, 'msg' => '提现申请不存在', 'data' => []];
        }

        $result = [
            'withdraw_id' => $withdrawInfo['id'],
            'withdraw_status' => $withdrawInfo['withdraw_status'],
            'status_text' => $this->modelWithdrawOrder->getWithdrawStatusText($withdrawInfo['withdraw_status']),
            'amount' => $withdrawInfo['amount'],
            'actual_amount' => $withdrawInfo['actual_amount'],
            'fee' => $withdrawInfo['fee'],
            'apply_time' => date('Y-m-d H:i:s', $withdrawInfo['apply_time']),
            'audit_time' => $withdrawInfo['audit_time'] ? date('Y-m-d H:i:s', $withdrawInfo['audit_time']) : '',
            'pay_time' => $withdrawInfo['pay_time'] ? date('Y-m-d H:i:s', $withdrawInfo['pay_time']) : '',
            'remark' => $withdrawInfo['remark'],
            'audit_remark' => $withdrawInfo['audit_remark'],
        ];

        return ['code' => 0, 'msg' => '获取成功', 'data' => $result];
    }

    /**
     * 批量审核提现
     */
    public function batchReview($data = [])
    {
        $ids = $data['ids'] ?? '';
        $status = $data['status'] ?? 0;
        $adminId = $data['admin_id'] ?? 0;
        $remark = $data['remark'] ?? '';

        if (empty($ids) || !in_array($status, [1, 3]) || !$adminId) {
            return ['code' => 1, 'msg' => '参数错误', 'data' => []];
        }

        $idArr = explode(',', $ids);

        try {
            \think\facade\Db::transaction(function () use ($idArr, $status, $adminId, $remark) {
                foreach ($idArr as $id) {
                    $this->withdrawReview(['withdraw_id' => $id, 'status' => $status, 'admin_id' => $adminId, 'remark' => $remark]);
                }
            });
            return ['code' => 0, 'msg' => '批量审核成功', 'data' => []];
        } catch (\Exception $e) {
            return ['code' => 1, 'msg' => '批量审核失败：' . $e->getMessage(), 'data' => []];
        }
    }
    
    /**
     * 获取查询条件
     * @param array $data 查询参数
     * @return array
     * @author 王勇程 <laughskydragon@qq.com>
     */
    public function getWhere($data = [])
    {
        $where = [];
        
        // 用户ID
        if (!empty($data['user_id'])) {
            $where['user_id'] = $data['user_id'];
        }
        
        // 状态
        if (isset($data['withdraw_status']) && $data['withdraw_status'] !== '') {
            $where['withdraw_status'] = $data['withdraw_status'];
        }
        
        // 提现方式
        if (!empty($data['withdraw_type'])) {
            $where['withdraw_type'] = $data['withdraw_type'];
        }
        
        // 申请时间范围
        if (!empty($data['start_time'])) {
            $startTime = strtotime($data['start_time']);
            $where['apply_time'] = ['>=', $startTime];
        }
        
        if (!empty($data['end_time'])) {
            $endTime = strtotime($data['end_time'] . ' 23:59:59');
            if (isset($where['apply_time'])) {
                $where['apply_time'] = ['between', [$where['apply_time'][1], $endTime]];
            } else {
                $where['apply_time'] = ['<=', $endTime];
            }
        }
        
        // 金额范围
        if (!empty($data['min_amount'])) {
            $where['amount'] = ['>=', $data['min_amount']];
        }
        
        if (!empty($data['max_amount'])) {
            if (isset($where['amount'])) {
                $where['amount'] = ['between', [$where['amount'][1], $data['max_amount']]];
            } else {
                $where['amount'] = ['<=', $data['max_amount']];
            }
        }
        
        return $where;
    }

    /**
     * 从系统配置获取提现配置（用户侧）
     */
    private function getUserWithdrawConfig()
    {
        $cfg = [
            'min_amount' => floatval(config('withdraw_min_amount') ?? 10),
            'max_amount' => floatval(config('withdraw_max_amount') ?? 5000),
            'fee_rate' => floatval(config('withdraw_fee_rate') ?? 0),
            'daily_limit' => floatval(config('withdraw_daily_limit') ?? 10000),
            'auto_audit' => intval(config('withdraw_auto_audit') ?? 0),
            'working_hours' => strval(config('withdraw_working_hours') ?? '09:00-18:00'),
            'working_days' => strval(config('withdraw_working_days') ?? '1,2,3,4,5'),
        ];
        $cfg['is_work_time'] = $this->isWorkTimeInternal($cfg);
        return $cfg;
    }

    /**
     * 计算手续费（基于配置）
     */
    private function calculateFeeInternal($amount, $cfg)
    {
        $ratePercent = floatval($cfg['fee_rate']);
        $rate = $ratePercent > 1 ? ($ratePercent / 100.0) : $ratePercent;
        $fee = $amount * $rate;
        return round($fee, 2);
    }

    /**
     * 判断是否工作时间
     */
    private function isWorkTimeInternal($cfg)
    {
        $workDays = array_map('intval', explode(',', $cfg['working_days']));
        $w = intval(date('N'));
        if (!in_array($w, $workDays)) { return false; }
        $parts = explode('-', $cfg['working_hours']);
        $start = strtotime($parts[0] ?? '09:00');
        $end = strtotime($parts[1] ?? '18:00');
        $now = strtotime(date('H:i'));
        return $now >= $start && $now <= $end;
    }
}
